﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WWWSiteHelper
{
    public class AutoCompletition
    {
        public static readonly AttributesProvider attributesProvider = AttributesProvider.Factory.GetInstance();
        private static readonly IList<Keys> arrows = new Keys[] { Keys.Up, Keys.Down, Keys.Left, Keys.Right }.ToList();
        private static readonly int radius = 256;
        private readonly DataGridView dataGridView;
        private TextBox currentTextBox = null;
        private IDictionary<string, string> currentAttributeToValue = null;

        public AutoCompletition(DataGridView dataGridView)
        {
            this.dataGridView = dataGridView;
            init();
        }

        private void init()
        {
            dataGridView.CellEndEdit += new DataGridViewCellEventHandler(dataGridView_CellEndEdit);
        }

        void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            updateRow(e.RowIndex);
            String attrs = generateAttributesText();
            HTMLUtilities.Localizator localizator
                = HTMLUtilities.LocalizeTag(currentTextBox.Text, currentTextBox.SelectionStart, radius);
            if (localizator != null)
            {
                TagAttributeValueKnowledge.FilledTag filledTag
                    = HTMLUtilities.getFirstTagAttributes(currentTextBox.Text.Substring(localizator.Begin, localizator.Length));
                currentTextBox.SelectionStart = localizator.Begin;
                currentTextBox.SelectionLength = localizator.Length;
                string result = "<" + filledTag.Tag + ("".Equals(attrs) ? "" : " " + attrs) + ">";
                currentTextBox.SelectedText = result;
                currentTextBox.SelectionStart = localizator.Begin + 1;
                currentTextBox.SelectionLength = 0;
            }
        }

        private String generateAttributesText()
        {
            SortedDictionary<string, string> toGen = new SortedDictionary<string, string>();
            foreach (KeyValuePair<string, string> entry in currentAttributeToValue)
            {
                if (!String.IsNullOrEmpty(entry.Key) && !String.IsNullOrEmpty(entry.Value))
                {
                    toGen[entry.Key] = entry.Value;
                }
            }
            String attrs = String.Join(" ", toGen
                .OrderBy(attrVal => attrVal.Key)
                .ToList()
                .Select(attrVal => attrVal.Key + "=\"" + attrVal.Value + "\""));
            return attrs;
        }

        private void updateRow(int p)
        {
            object attribute = dataGridView[0, p].Value;
            object value = dataGridView[1, p].Value;
            if (attribute == null || "".Equals(attribute))
            {
                return;
            }
            else
            {
                if (value == null)
                {
                    value = "";
                }
                currentAttributeToValue[attribute.ToString()] = value.ToString();
                dataGridView[0, p].ReadOnly = true;
            }
        }

        public void AutoComplete(object sender, KeyEventArgs e)
        {
            dataGridView.Visible = false;
            this.currentTextBox = null;
            if (e != null && ' ' <= Convert.ToChar(e.KeyValue))
            {
                TextBox textBox = (TextBox)sender;
                this.currentTextBox = textBox;
                String text = textBox.Text;
                int separator = -1;
                if (textBox.SelectionLength == 0)
                {
                    int down = Math.Max(textBox.SelectionStart - 64, 0);
                    for (int i = textBox.SelectionStart - 1; i >= down; --i)
                    {
                        if (Char.IsWhiteSpace(text[i]))
                        {
                            separator = i;
                        }
                        else if (text[i] == '>')
                        {
                            break;
                        }
                        else if (text[i] == '<')
                        {
                            if (separator == -1)
                            {
                                int selectionStart = i + 1;
                                int selectionLength = textBox.SelectionStart - (i + 1);
                                String tagPrefix = text.Substring(selectionStart, selectionLength);
                                if (arrows.Contains(e.KeyCode))
                                {
                                    String tmp = text.Substring(i);
                                    tmp.Substring(0, tmp.IndexOf('>') + 1);
                                    showAttributes(tmp);
                                    System.Console.WriteLine("showattribute: " + tmp);
                                }
                                else
                                {
                                    TagAttributeKnowledge.BasicTag help = attributesProvider.GetHint(tagPrefix);
                                    if (help != null)
                                    {
                                        System.Console.WriteLine("tagPrefix: " + tagPrefix + " help: " + help);
                                        textBox.SelectionStart = selectionStart;
                                        textBox.SelectionLength = selectionLength;
                                        string textToSet = help.Name + ">";
                                        if (!help.SelfClosing)
                                        {
                                            textToSet += "</" + help.Name + ">";
                                        }
                                        textBox.SelectedText = textToSet;
                                        textBox.SelectionStart = selectionStart + selectionLength;
                                        textBox.SelectionLength = 2 * help.Name.Length + 4 - selectionLength;
                                    }
                                    showAttributes("");
                                }
                            }
                            else if (separator != -1)
                            {
                                String tagName = text.Substring(i + 1, separator - (i + 1));
                                if (!arrows.Contains(e.KeyCode))
                                {
                                    for (int j = textBox.SelectionStart - 1; j >= 0; --j)
                                    {
                                        if (text[j] == '=')
                                        {
                                            break;
                                        }
                                        else if (Char.IsWhiteSpace(text[j]))
                                        {
                                            int selectionStart = j + 1;
                                            int selectionLength = textBox.SelectionStart - (j + 1);
                                            String attributePrefix = text.Substring(selectionStart, selectionLength);
                                            String help = attributesProvider.GetHint(tagName, attributePrefix);
                                            if (help != null)
                                            {
                                                if (!attributePrefix.Equals(help))
                                                {
                                                    textBox.SelectionStart = selectionStart;
                                                    textBox.SelectionLength = selectionLength;
                                                    textBox.SelectedText = help;
                                                    textBox.SelectionStart = selectionStart + selectionLength;
                                                    textBox.SelectionLength = help.Length - selectionLength;
                                                }
                                            }
                                        }
                                    }
                                }
                                String tmp = text.Substring(i);
                                tmp.Substring(0, tmp.IndexOf('>') + 1);
                                showAttributes(tmp);
                            }
                            else
                            {
                                showAttributes("");
                            }
                            return;
                        }
                    }
                }
            }
        }

        private void showAttributes(string full)
        {
            TagAttributeValueKnowledge.FilledTag tagAttributes = HTMLUtilities.getFirstTagAttributes(full);
            if (tagAttributes.Tag == null)
            {
                return;
            }
            SortedDictionary<string, string> attrToVal = new SortedDictionary<string, string>(tagAttributes.AttributeToValue.ToDictionary(
                entry => entry.Key, entry => entry.Value));
            List<String> originAttrToVal = attributesProvider.GetAttributes(tagAttributes.Tag);
            List<KeyValuePair<string, string>> result = generateAllAttributeToValue(attrToVal, originAttrToVal);
            this.currentAttributeToValue = result.ToDictionary(entry => entry.Key, entry => entry.Value);
            updateDataGridView(result);
        }

        private static List<KeyValuePair<string, string>> generateAllAttributeToValue(SortedDictionary<string, string> userAttrToVal, List<String> originAttrToVal)
        {
            List<KeyValuePair<string, string>> result = userAttrToVal
                .ToList()
                .Union(
                    originAttrToVal
                    .SelectMany(attr =>
                        (userAttrToVal.Keys.Contains(attr) ? new string[] { }.ToList() : new string[] { attr }.ToList()))
                    .Select(attr => new KeyValuePair<string, string>(attr, ""))
                    .ToList())
                .ToList();
            return result;
        }

        private void updateDataGridView(List<KeyValuePair<string, string>> attributeToValue)
        {
            dataGridView.RowCount = 1;
            foreach (KeyValuePair<string, string> attrVal in attributeToValue)
            {
                dataGridView.Rows.Add(attrVal.Key, attrVal.Value);
                int len = dataGridView.Rows.Count - 2;
                dataGridView.Rows[len].Cells[0].ReadOnly = true;
                dataGridView.Rows[len].Cells[1].ReadOnly = false;
            }
            dataGridView.Visible = true;
        }
    }
}
